package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.repository.StrategyEsRepository;
import cn.wolfcode.luowowo.search.service.IStrategyEsService;
import cn.wolfcode.luowowo.search.template.StrategyTemplate;
import cn.wolfcode.luowowo.search.vo.StatisVO;
import com.alibaba.dubbo.config.annotation.Service;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.*;

@Service
public class StrategyEsServiceImpl implements IStrategyEsService {

    @Autowired
    private StrategyEsRepository strategyEsRepository;

    @Override
    public void saveOrUpdate(StrategyTemplate template) {
        strategyEsRepository.save(template);
    }

    @Override
    public List<Map<String, Object>> queryThemeCommend() {
        // 步骤1: 通过es 分组查询, 查询到主题列表: themeid themeName count
        List<StatisVO> list = this.getStatsVoList("themeId", "themeName", "themeGroup");

        // 优化2: 取前面10
        if(list.size() > 10){
            list = list.subList(0, 10);
        }


        // 步骤2:通过主题id, themeid查询目的地集合
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> map = null;
        for (StatisVO statisVO : list) {
            map = new HashMap<>();
            // vo 主题
            map.put("theme", statisVO);
            // 某一个主题下面, 关联的目的地集合
            List<StatisVO> dests = this.getDestByThemeId(statisVO.getId());
            map.put("dests", dests);
            data.add(map);
        }
        // 步骤3:通过步骤1, 步骤2数据, 组装成最终的data数据, 并返回
        return data;
    }

    @Override
    public List<StatisVO> queryConditionChina() {
        return this.getStatsVoList("provinceId", "provinceName", "provinceGroup");
    }

    @Override
    public List<StatisVO> queryConditionAbroad() {
        return this.getStatsVoList("countryId", "countryName", "countryGroup");
    }

    @Override
    public List<StatisVO> queryConditionTheme() {
        return this.getStatsVoList("themeId", "themeName", "themeGroup");
    }

    @Override
    public Page query(SearchQueryObject qo) {
        TermQueryBuilder query = null;

        //分页参数对象
        PageRequest of = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize(), Sort.Direction.DESC, qo.getOrderBy());

        if (qo.getType() == SearchQueryObject.CONDITION_TYPE_COUNTRY){
            //国家
            query = QueryBuilders.termQuery("countryId", qo.getTypeValue());
        }else if (qo.getType() == SearchQueryObject.CONDITION_TYPE_PROVINCE){
            //省份
            query = QueryBuilders.termQuery("provinceId", qo.getTypeValue());
        }else if (qo.getType() == SearchQueryObject.CONDITION_TYPE_THEME){
            //主题
            query = QueryBuilders.termQuery("themeId", qo.getTypeValue());
        }

        if(query == null){
            return strategyEsRepository.findAll(of);
        }else {
            return strategyEsRepository.search(query, of);
        }
    }

    @Override
    public List<StrategyTemplate> findByDestName(String name) {
        return strategyEsRepository.findByDestName(name);
    }

    private List<StatisVO> getDestByThemeId(Long themeId) {
        List<StatisVO> vos = new ArrayList<>();
        List<StrategyTemplate> templates = strategyEsRepository.findByThemeId(themeId);
        // 上面查询查到时 es攻略list集合, 前面需要只是目的地id 目的地name

        // 优化3: 目的地去除重复
        List<String> list = new ArrayList<>();

        for (StrategyTemplate template : templates) {
            if(!list.contains(template.getDestName())){
                StatisVO statisVO = new StatisVO();
                statisVO.setId(template.getId());
                statisVO.setName(template.getDestName());
                vos.add(statisVO);
                list.add(template.getDestName());
            }
        }
        return vos;
    }

    // 统计分组集合
    private List<StatisVO> getStatsVoList(String idFieId, String nameFieId, String groupName){
        // 分组列对象集合
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        idSource.field(idFieId);
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        nameSource.field(nameFieId);
        sources.add(idSource);
        sources.add(nameSource);
        // 构造分组语法
        CompositeAggregationBuilder compositeAggregationBuilder = new CompositeAggregationBuilder(groupName, sources);

        // es查询语句构建类
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.addAggregation(compositeAggregationBuilder);
        // 分页
        builder.withPageable(PageRequest.of(0, 1));
        // 明确指定查哪个索引, 哪个类型
        builder.withIndices(StrategyTemplate.INDEX_NAME);
        builder.withTypes(StrategyTemplate.TYPE_NAME);


        // 执行查询语句, 返回结果
        AggregatedPage<StrategyTemplate> search = (AggregatedPage<StrategyTemplate>) strategyEsRepository.search(builder.build());
        InternalComposite themeGroup = (InternalComposite) search.getAggregation(groupName);

        List<StatisVO> list = new ArrayList<>();

        for (CompositeAggregation.Bucket bucket : themeGroup.getBuckets()) {
            Long id = Long.parseLong(bucket.getKey().get("id").toString());
            String name = bucket.getKey().get("name").toString();
            Long count = bucket.getDocCount();

            StatisVO statisVO = new StatisVO();
            statisVO.setId(id);
            statisVO.setName(name);
            statisVO.setCount(count);
            list.add(statisVO);
        }

        // 优化1: 排序 -- list集合排序
        Collections.sort(list, new Comparator<StatisVO>() {
            // 比较器, 比较元素在集合中位置
            // compare比较方法, 返回
            // < 0 : 表示小于
            // = 0 : 表示等于
            // > 0 : 表示大于
            @Override
            public int compare(StatisVO statisVO, StatisVO t1) {
                // 倒序排
                Long ret = t1.getCount() - statisVO.getCount();
                return ret.intValue();
            }
        });
        return list;
    }
}
